//
// Authors:
// Miguel de Icaza (miguel@ximian.com)
// Dick Porter (dick@ximian.com)
// Marek Safar (marek.safar@gmail.com)
//
// (C) 2001, 2002, 2003 Ximian, Inc. (http://www.ximian.com)
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
// Copyright (C) 2012 Xamarin Inc (http://www.xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

#ifndef CultureInfo_h
#define CultureInfo_h

#include <System/ICloneable.h>
#include <System/IFormatProvider.h>
#include <System/Collections/Generic/Dictionary.h>
#include <System/String.h>
#include <System/Array.h>
#include <System/Type.h>
#include <System/Int32.h>
#include <System/Globalization/CultureTypes.h>
#include <System/Globalization/GregorianCalendarTypes.h>
#include <System/Globalization/Calendar.h>

#define __CultureInfo__ConstructorInitializer									\
	: PROP3GET_INIT(CultureInfo, UseUserOverride)								\
	, PROP3GET_INIT(CultureInfo, TwoLetterISOLanguageName)						\
	, PROP3GET_INIT(CultureInfo, ThreeLetterWindowsLanguageName)				\
	, PROP3GET_INIT(CultureInfo, ThreeLetterISOLanguageName)					\
	, PROP3GET_INIT(CultureInfo, textInfo)										\
	, PROP3GET_INIT(CultureInfo, Parent)										\
	, PROP3GET_INIT(CultureInfo, OptionalCalendars)								\
	, PROP3GET_INIT(CultureInfo, calendar)										\
	, PROP3GET_INIT(CultureInfo, NativeCalendarName)							\
	, PROP3GET_INIT(CultureInfo, NativeName)									\
	, PROP3GET_INIT(CultureInfo, Name)											\
	, PROP3GET_INIT(CultureInfo, LCID)											\
	, PROP3GET_INIT(CultureInfo, KeyboardLayoutId)								\
	, PROP3GET_INIT(CultureInfo, IetfLanguageTag)								\
	, PROP3GET_INIT(CultureInfo, cultureTypes)									\
	, PROP3GET_INIT(CultureInfo, Territory)										\
	, PROP3GET_INIT(CultureInfo, DisplayName)									\
	, PROP3GET_INIT(CultureInfo, EnglishName)									\
	, PROP3GET_INIT(CultureInfo, IsReadOnly)									\
	, PROP3GET_INIT(CultureInfo, IsNeutralCulture)								\
	, PROP3_INIT(CultureInfo, NumberFormat)						

namespace Riccsson
{
	namespace System
	{
		namespace Globalization
		{
			// Not implemented.
			class NumberFormatInfo;
			class DateTimeFormatInfo;
			class TextInfo;
			class CompareInfo {};
			class GregorianCalendar {};

			class CultureInfo
				: public Riccsson::System::ICloneable
				, public Riccsson::System::IFormatProvider
				, public Riccsson::System::Object
			{
				
				
				PROP3GET(CultureInfo, bool, UseUserOverride)
				PROP3GET(CultureInfo, GC_PTR<string>, TwoLetterISOLanguageName)
				PROP3GET(CultureInfo, GC_PTR<string>, ThreeLetterWindowsLanguageName)
				PROP3GET(CultureInfo, GC_PTR<string>, ThreeLetterISOLanguageName)
				PROP3GET(CultureInfo, GC_PTR<TextInfo>, textInfo)
				PROP3GET(CultureInfo, GC_PTR<CultureInfo>, Parent)
				PROP3GET(CultureInfo, GC_PTR<Array<GC_PTR<Calendar>>>, OptionalCalendars)
				PROP3GET(CultureInfo, GC_PTR<Calendar>, calendar)
				PROP3GET(CultureInfo, GC_PTR<string>, NativeCalendarName)
				PROP3GET(CultureInfo, GC_PTR<string>, NativeName)
				PROP3GET(CultureInfo, GC_PTR<string>, Name)
				PROP3GET(CultureInfo, int, LCID)
				PROP3GET(CultureInfo, int, KeyboardLayoutId)
				PROP3GET(CultureInfo, GC_PTR<string>, IetfLanguageTag)
				PROP3GET(CultureInfo, CultureTypes, cultureTypes)
				PROP3GET(CultureInfo, GC_PTR<string>, Territory)
				PROP3GET_STATIC(CultureInfo, GC_PTR<CultureInfo>, CurrentUICulture) 
				PROP3GET_STATIC(CultureInfo, GC_PTR<CultureInfo>, CurrentCulture)
				PROP3GET_STATIC(CultureInfo, GC_PTR<CultureInfo>, InvariantCulture)
				PROP3GET(CultureInfo, GC_PTR<string>, DisplayName)
				PROP3GET(CultureInfo, GC_PTR<string>, EnglishName)
				PROP3GET_STATIC(CultureInfo, GC_PTR<CultureInfo>, InstalledUICulture)
				PROP3GET(CultureInfo, bool, IsReadOnly)
				PROP3GET(CultureInfo, bool, IsNeutralCulture)
				PROP3(CultureInfo, GC_PTR<NumberFormatInfo>, NumberFormat)

				static volatile GC_PTR<CultureInfo> invariant_culture_info;
				static GC_PTR<object> shared_table_lock;
				static GC_PTR<CultureInfo> default_current_culture;

				REGISTER_CLASS(CultureInfo);

				bool m_isReadOnly;
				int  cultureID;
				int parent_lcid;
				int datetime_index;
				int number_index;
				int default_calendar_type;
				bool m_useUserOverride;
				volatile GC_PTR<NumberFormatInfo> numInfo;
				volatile GC_PTR<DateTimeFormatInfo> dateTimeInfo;
				volatile GC_PTR<TextInfo> _textInfo;
				private: GC_PTR<string> m_name;
		
				private: GC_PTR<string> englishname;
				private: GC_PTR<string> nativename;
				private: GC_PTR<string> iso3lang;
				private: GC_PTR<string> iso2lang;
				private: GC_PTR<string> win3lang;
				private: GC_PTR<string> territory;
				GC_PTR<Array<GC_PTR<string>>> native_calendar_names;

				volatile GC_PTR<CompareInfo> compareInfo;
				private: unsafe readonly void *textinfo_data;

				int m_dataItem;		// MS.NET serializes this->

				GC_PTR<Calendar> _calendar;

				GC_PTR<CultureInfo> parent_culture;

				// Deserialized instances will set this to false
				bool constructed;

				// Used by Thread.set_CurrentCulture
				/*internal*/ GC_PTR<Array<byte>> cached_serialized_form;

				COPY_CONSTRUCTOR(CultureInfo)
				{
					throw;
				}
		
				/*internal*/ static /*const*/ int InvariantCultureId;
				static /*const*/ int CalendarTypeBits;

				static /*const*/ GC_PTR<string> MSG_READONLY;
				
				public: static PROP3_GET(GC_PTR<CultureInfo>, InvariantCulture)
				{
					return invariant_culture_info;
				}

				public: static PROP3_GET(GC_PTR<CultureInfo>, CurrentCulture)
				{
					//return Thread::CurrentThread::CurrentCulture;
					throw;
				}

				public: static PROP3_GET(GC_PTR<CultureInfo>, CurrentUICulture) 
				{
					//return Thread::CurrentThread::CurrentUICulture;
					throw;
				}

				/*internal*/ static GC_PTR<CultureInfo> ConstructCurrentCulture ()
				{
					if (default_current_culture != null)
						return default_current_culture;

					var locale_name = get_current_locale_name ();
					GC_PTR<CultureInfo> ci = null;
					try {
						ci = CreateSpecificCulture (locale_name);
					} catch(...) {
					}

					if (ci == null) {
						ci = InvariantCulture;
					} else {
						ci->m_isReadOnly = true;
						ci->m_useUserOverride = true;
					}

					default_current_culture = ci;
					return ci;
				}

				/*internal*/ static GC_PTR<CultureInfo> ConstructCurrentUICulture ()
				{
					return ConstructCurrentCulture ();
				}
				
				// it is used for RegionInfo.
				/*internal*/ PROP3_GET(GC_PTR<string>, Territory)
				{
					return territory;
				}

				// FIXME: It is implemented, but would be hell slow.
				public: PROP3_GET(CultureTypes, cultureTypes)
				{
					//CultureTypes ret = (CultureTypes) 0;
					//foreach (CultureTypes v : Enum::GetValues (typeof (CultureTypes)))
					//	if (Array::IndexOf (GetCultures (v), this) >= 0)
					//		ret |= v;
					//return ret;
					throw;
				}

				public: GC_PTR<CultureInfo> GetConsoleFallbackUICulture ()
				{
					//// as documented in MSDN ...
					//switch (Name) {
					//case "ar": case "ar-BH": case "ar-EG": case "ar-IQ":
					//case "ar-JO": case "ar-KW": case "ar-LB": case "ar-LY":
					//case "ar-QA": case "ar-SA": case "ar-SY": case "ar-AE":
					//case "ar-YE":
					//case "dv": case "dv-MV":
					//case "fa": case "fa-IR":
					//case "gu": case "gu-IN":
					//case "he": case "he-IL":
					//case "hi": case "hi-IN":
					//case "kn": case "kn-IN":
					//case "kok": case "kok-IN":
					//case "mr": case "mr-IN":
					//case "pa": case "pa-IN":
					//case "sa": case "sa-IN":
					//case "syr": case "syr-SY":
					//case "ta": case "ta-IN":
					//case "te": case "te-IN":
					//case "th": case "th-TH":
					//case "ur": case "ur-PK":
					//case "vi": case "vi-VN":
					//	return GetCultureInfo ("en");
					//case "ar-DZ": case "ar-MA": case "ar-TN":
					//	return GetCultureInfo ("fr");
					//}
					//return (CultureTypes & CultureTypes.WindowsOnlyCultures) != 0 ? CultureInfo.InvariantCulture : this;
					throw;
				}
						
					// There could be more consistent way to implement
					// it, but right now it works just fine with this->..
				public: PROP3_GET(GC_PTR<string>, IetfLanguageTag)
				{
					//switch (Name)
					//{
					//case "zh-CHS":
					//	return "zh-Hans";
					//case "zh-CHT":
					//	return "zh-Hant";
					//default:
					//	return Name;
					//}
					throw;
				}
						
				// For specific cultures it basically returns LCID.
				// For neutral cultures it is mapped to the default(?) specific
				// culture, where the LCID of the specific culture seems to be
				// n + 1024 by default. zh-CHS is the only exception which is 
				// mapped to 2052, not 1028 (zh-CHT is mapped to 1028 instead).
				// There are very few exceptions, here I simply list them here.
				// It is Windows-specific property anyways, so no worthy of
				// trying to do some complex things with locale-builder.
				public: virtual PROP3_GET(int, KeyboardLayoutId)
				{
					switch (LCID) {
					case 4: // zh-CHS (neutral)
						return 2052;
					case 1034: // es-ES Spanish 2
						return 3082;
					case 31748: // zh-CHT (neutral)
						return 1028;
					case 31770: // sr (neutral)
						return 2074;
					default:
						return LCID < 1024 ? LCID + 1024 : LCID;
					}
				}
						
				public: virtual PROP3_GET(int, LCID)
				{
					return cultureID;
				}
						
				public: virtual PROP3_GET(GC_PTR<string>, Name)
				{
					return(m_name);
				}

				public: virtual PROP3_GET(GC_PTR<string>, NativeName)
				{
					if (!constructed) Construct ();
					return nativename;
				}
						
				/*internal*/ PROP3_GET(GC_PTR<string>, NativeCalendarName)
				{
					if (!constructed) Construct ();
					return (**native_calendar_names)[(default_calendar_type >> CalendarTypeBits) - 1];
				}
		
				public: virtual PROP3_GET(GC_PTR<Calendar>, calendar)
				{
					if (_calendar == null) {
						if (!constructed) Construct ();
						_calendar = CreateCalendar (default_calendar_type);
					}

					return _calendar;
				}
						
				public: virtual PROP3_GET(GC_PTR<Array<GC_PTR<Calendar>>>, OptionalCalendars)
				{
					GC_PTR<Array<GC_PTR<Calendar>>> output( new Array<GC_PTR<Calendar>>(1) );
					output->Insert(0, _calendar);
					return output;
				}
						
				public: virtual PROP3_GET(GC_PTR<CultureInfo>, Parent)
				{
					//if (parent_culture == null) {
					//	if (!constructed)
					//		Construct ();
					//	if (parent_lcid == cultureID) {
					//		//
					//		// Parent lcid is same but culture info is not for legacy zh culture
					//		//
					//		if (parent_lcid == 0x7C04 && EnglishName.get()->EndsWith (" Legacy", StringComparison::Ordinal))
					//			return parent_culture = new CultureInfo ("zh-Hant");
					//
					//		return null;
					//	}
					//
					//	if (parent_lcid == InvariantCultureId)
					//		parent_culture = InvariantCulture;
					//	else if (cultureID == InvariantCultureId)
					//		parent_culture = this;
					//	else
					//		parent_culture = new CultureInfo (parent_lcid);
					//}
					//return parent_culture;
					throw;
				}
						
				public: virtual PROP3_GET(GC_PTR<TextInfo>, textInfo)
				{
					//if (_textInfo == null) {
					//	if (!constructed) Construct ();
					//	lock (this) {
					//		if(_textInfo == null) {
					//			_textInfo = CreateTextInfo (m_isReadOnly);
					//		}
					//	}
					//}
					//
					//return(_textInfo);
					throw;
				}
						
				public: virtual PROP3_GET(GC_PTR<string>, ThreeLetterISOLanguageName)
				{
					if (!constructed) Construct ();
					return iso3lang;
				}

				public: virtual PROP3_GET(GC_PTR<string>, ThreeLetterWindowsLanguageName)
				{
					if (!constructed) Construct ();
					return(win3lang);
				}

				public: virtual PROP3_GET(GC_PTR<string>, TwoLetterISOLanguageName)
				{
					if (!constructed) Construct ();
					return(iso2lang);
				}

				public: PROP3_GET(bool, UseUserOverride)
				{
					return m_useUserOverride;
				}

				public: void ClearCachedData()
				{
					//Thread::CurrentThread::CurrentCulture = null;
					//Thread::CurrentThread::CurrentUICulture = null;
					throw;
				}

				public: virtual GC_PTR<object> Clone()
				{
					//if (!constructed) Construct ();
					//CultureInfo ci=(CultureInfo)MemberwiseClone ();
					//ci.m_isReadOnly=false;
					//ci.cached_serialized_form=null;
					//if (!IsNeutralCulture) {
					//	ci.NumberFormat = (NumberFormatInfo)NumberFormat.Clone ();
					//	ci.DateTimeFormat = (DateTimeFormatInfo)DateTimeFormat.Clone ();
					//}
					//return(ci);
					throw;
				}

				public: override bool Equals (object* value)
				{
					GC_PTR<CultureInfo> b = (CultureInfo*)value;
			
					if (b != null)
						return b->cultureID == cultureID;
					return false;
				}

				public: static GC_PTR<Array<GC_PTR<CultureInfo>>> GetCultures(CultureTypes types)
				{
					bool neutral=(((int)types & (int)CultureTypes::NeutralCultures)!=0);
					bool specific=(((int)types & (int)CultureTypes::SpecificCultures)!=0);
					bool installed=(((int)types & (int)CultureTypes::InstalledWin32Cultures)!=0);  // TODO

					GC_PTR<Array<GC_PTR<CultureInfo>>> infos = internal_get_cultures (neutral, specific, installed);
					// The runtime returns a NULL in the first position of the array when
					// 'neutral' is true. We fill it in with a clone of InvariantCulture
					// since it must not be read-only
					if (neutral && infos->Length > 0 && (**infos)[0] == null) {
						(**infos)[0] = (CultureInfo*)*InvariantCulture.get()->Clone ();
					}

					return infos;
				}

				public: override int GetHashCode ()
				{
					return Int32(cultureID).GetHashCode ();
				}

				public: static GC_PTR<CultureInfo> ReadOnly(CultureInfo* ci)
				{
					//if(ci==null) {
					//	throw ArgumentNullException("ci");
					//}
					//
					//if(ci->m_isReadOnly) {
					//	return(ci);
					//} else {
					//	GC_PTR<CultureInfo> new_ci=(CultureInfo*)*ci->Clone ();
					//	new_ci->m_isReadOnly=true;
					//	if (new_ci->numInfo != null)
					//		new_ci->numInfo = NumberFormatInfo::ReadOnly (new_ci->numInfo);
					//	if (new_ci->dateTimeInfo != null)
					//		new_ci->dateTimeInfo = DateTimeFormatInfo::ReadOnly (new_ci->dateTimeInfo);
					//	if (new_ci->_textInfo != null)
					//		new_ci->_textInfo = TextInfo::ReadOnly (new_ci->_textInfo);
					//	return(new_ci);
					//}
					throw;
				}

				public: override GC_PTR<string> ToString()
				{
					return(m_name);
				}
		
				public: virtual PROP3_GET(GC_PTR<CompareInfo>, compareInfo)
				{
					//if(compareInfo==null) {
					//	if (!constructed)
					//		Construct ();
					//
					//	lock (this) {
					//		if(compareInfo==null) {
					//			compareInfo=new CompareInfo (this);
					//		}
					//	}
					//}
					//
					//return(compareInfo);
					throw;
				}

				public: virtual PROP3_GET(bool, IsNeutralCulture)
				{
					if (cultureID == InvariantCultureId)
						return false;

					if (!constructed) Construct ();
					return territory == null;
				}

				/*internal*/ void CheckNeutral ()
				{
					if (IsNeutralCulture) {
						throw NotSupportedException (string("Culture \"") + **m_name + "\" is " +
								"a neutral culture. It can not be used in formatting " +
								"and parsing and therefore cannot be set as the thread's " +
								"current culture.");
					}
				}

				public: virtual PROP3_GET(GC_PTR<NumberFormatInfo>, NumberFormat)
				{
					//if (!constructed) Construct ();
					//CheckNeutral ();
					//if (numInfo == null){
					//	lock (this){
					//		if (numInfo == null) {
					//			numInfo = new NumberFormatInfo (m_isReadOnly);
					//			construct_number_format ();
					//		}
					//	}
					//}
					//
					//return numInfo;
					throw;
				}
				public: virtual PROP3_SET(GC_PTR<NumberFormatInfo>, NumberFormat)
				{
					if (!constructed) Construct ();
					if (m_isReadOnly) throw InvalidOperationException(MSG_READONLY);

					if (value == null)
						throw ArgumentNullException ("NumberFormat");
				
					numInfo = value;
				}

				public: virtual PROP3_GET(GC_PTR<DateTimeFormatInfo>, DateTimeFormat)
				{
					//if (dateTimeInfo != null)
					//	return dateTimeInfo;
					//
					//if (!constructed) Construct ();
					//CheckNeutral ();
					//
					//// TODO: Have to lock because construct_datetime_format is not atomic
					//lock (this) {
					//	if (cultureID == InvariantCultureId && m_isReadOnly)
					//		dateTimeInfo = DateTimeFormatInfo::InvariantInfo;
					//	else if (dateTimeInfo == null) {
					//		dateTimeInfo = new DateTimeFormatInfo (this, m_isReadOnly);
					//		if (cultureID != InvariantCultureId)
					//			construct_datetime_format ();
					//	}
					//}
					//
					//return dateTimeInfo;
					throw;
				}
				public: virtual PROP3_SET(GC_PTR<DateTimeFormatInfo>, DateTimeFormat)
				{
					if (!constructed) Construct ();
					if (m_isReadOnly) throw InvalidOperationException(MSG_READONLY);

					if (value == null)
						throw ArgumentNullException ("DateTimeFormat");
				
					dateTimeInfo = value;
				}

				public: virtual PROP3_GET(GC_PTR<string>, DisplayName)
				{
					// Mono is not localized and will always return english name regardless of OS locale
					return EnglishName;
				}

				public: virtual PROP3_GET(GC_PTR<string>, EnglishName)
				{
					if (!constructed) Construct ();
					return englishname;
				}

				public: static PROP3_GET(GC_PTR<CultureInfo>, InstalledUICulture)
				{
					return ConstructCurrentCulture ();
				}

				public: PROP3_GET(bool, IsReadOnly)
				{
					return m_isReadOnly;
				}
		

				// 
				// IFormatProvider implementation
				//
				public: virtual GC_PTR<object> GetFormat( Type* formatType )
				{
					//GC_PTR<object> format = null;
					//
					//if ( formatType == typeof(NumberFormatInfo) )
					//	format = NumberFormat;
					//else if ( formatType == typeof(DateTimeFormatInfo) )
					//	format = DateTimeFormat;
					//
					//return format;
					throw;
				}
		
				void Construct ()
				{
					construct_internal_locale_from_lcid (cultureID);
					constructed = true;
				}

				private: /*extern*/ bool construct_internal_locale_from_lcid (int lcid);
				private: /*extern*/ bool construct_internal_locale_from_name (string* name);
				private: /*extern*/ static GC_PTR<string> get_current_locale_name ();
				private: /*extern*/ static GC_PTR<Array<GC_PTR<CultureInfo>>> internal_get_cultures (bool neutral, bool specific, bool installed);
				private: /*extern*/ void construct_datetime_format ();
				private: /*extern*/ void construct_number_format ();

				private: void ConstructInvariant (bool read_only)
				{
					//cultureID = InvariantCultureId;
					//
					///* NumberFormatInfo defaults to the invariant data */
					//numInfo=NumberFormatInfo::InvariantInfo;
					//
					//if (!read_only) {
					//	numInfo = (NumberFormatInfo*) numInfo.Clone ();
					//}
					//
					//_textInfo = CreateTextInfo (read_only);
					//
					//m_name=String::Empty;
					//englishname=
					//nativename="Invariant Language (Invariant Country)";
					//iso3lang="IVL";
					//iso2lang="iv";
					//win3lang="IVL";
					//default_calendar_type = 1 << CalendarTypeBits;
					throw;
				}

				private: /*unsafe*/ GC_PTR<TextInfo> CreateTextInfo (bool readOnly)
				{
					//return new TextInfo (this, cultureID, this->textinfo_data, readOnly);
					throw;
				}

				public: CultureInfo (int culture)		
					__CultureInfo__ConstructorInitializer
				{
					init (culture, true, false);
				}

				public: CultureInfo (int culture, bool useUserOverride)
					__CultureInfo__ConstructorInitializer
				{
					init (culture, useUserOverride, false);
				}

				private: CultureInfo (int culture, bool useUserOverride, bool read_only)
					__CultureInfo__ConstructorInitializer
				{
					init (culture, useUserOverride, read_only);
				}

				private: void init(int culture, bool useUserOverride, bool read_only)
				{
					//if (culture < 0)
					//	throw ArgumentOutOfRangeException ("culture", string("Positive ") + "number required.");
					//
					//constructed = true;
					//m_isReadOnly = read_only;
					//m_useUserOverride = useUserOverride;
					//
					//if (culture == InvariantCultureId) {
					//	/* Short circuit the invariant culture */
					//	ConstructInvariant (read_only);
					//	return;
					//}
					//
					//if (!construct_internal_locale_from_lcid (culture)) {
					//	throw CultureNotFoundException ("culture", 
					//		String::Format ("Culture ID {0} (0x{0:X4}) is not a " +
					//				"supported culture.", culture));
					//}
					throw;
				}

				public: CultureInfo(string* name) __CultureInfo__ConstructorInitializer
				{
					init2 (name, true, false);
				}

				public: CultureInfo (string* name, bool useUserOverride) __CultureInfo__ConstructorInitializer
				{
					init2 (name, useUserOverride, false);
				}

				private: CultureInfo (string* name, bool useUserOverride, bool read_only)
					__CultureInfo__ConstructorInitializer
				{
					init2(name, useUserOverride, read_only);
				}

				private: void init2 (string* name, bool useUserOverride, bool read_only)
				{
					//if (name == null)
					//	throw ArgumentNullException ("name");
					//
					//constructed = true;
					//m_isReadOnly = read_only;
					//m_useUserOverride = useUserOverride;
					//
					//if (name->Length == 0) {
					//	/* Short circuit the invariant culture */
					//	ConstructInvariant (read_only);
					//	return;
					//}
					//
					//if (!construct_internal_locale_from_name (name->ToLowerInvariant ())) {
					//	throw CreateNotFoundException (name);
					//}
					throw;
				}

				// This is used when creating by specific name and creating by
				// current locale so we can initialize the object without
				// doing any member initialization
				private: CultureInfo () __CultureInfo__ConstructorInitializer
				{
					constructed = true;
				}

				static GC_PTR<Riccsson::System::Collections::Generic::Dictionary<int, GC_PTR<CultureInfo>>> shared_by_number;
				static GC_PTR<Riccsson::System::Collections::Generic::Dictionary<GC_PTR<string>, GC_PTR<CultureInfo>>> shared_by_name;
		
				static void insert_into_shared_tables (CultureInfo* c)
				{
					//if (shared_by_number == null){
					//	shared_by_number = new Riccsson::System::Collections::Generic::Dictionary<int, GC_PTR<CultureInfo>> ();
					//	shared_by_name = new Riccsson::System::Collections::Generic::Dictionary<GC_PTR<string>, GC_PTR<CultureInfo>> ();
					//}
					//shared_by_number [c->cultureID] = c;
					//shared_by_name [c->m_name] = c;
					throw;
				}
		
				public: static GC_PTR<CultureInfo> GetCultureInfo (int culture)
				{
					//GC_PTR<CultureInfo> c;
					//
					//lock (shared_table_lock){
					//	if (shared_by_number != null) {
					//		if (shared_by_number.TryGetValue (culture, out c))
					//			return c;
					//	}
					//
					//	c = new CultureInfo (culture, false, true);
					//	insert_into_shared_tables (c);
					//	return c;
					//}
					throw;
				}

				public: static GC_PTR<CultureInfo> GetCultureInfo (string* name)
				{
					//if (name == null)
					//	throw ArgumentNullException ("name");
					//
					//CultureInfo c;
					//lock (shared_table_lock){
					//	if (shared_by_name != null){
					//		if (shared_by_name.TryGetValue (name, out c))
					//			return c;
					//	}
					//	c = new CultureInfo (name, false, true);
					//	insert_into_shared_tables (c);
					//	return c;
					//}
					throw;
				}

				public: static GC_PTR<CultureInfo> GetCultureInfo (string* name, string* altName) {
					//if (name == null)
					//	throw ArgumentNullException ("null");
					//if (altName == null)
					//	throw ArgumentNullException ("null");
					//
					//return GetCultureInfo (name);
					throw;
				}

				public: static GC_PTR<CultureInfo> GetCultureInfoByIetfLanguageTag (string* name)
				{
					//// There could be more consistent way to implement
					//// it, but right now it works just fine with this->..
					//switch (name) {
					//case "zh-Hans":
					//	return GetCultureInfo ("zh-CHS");
					//case "zh-Hant":
					//	return GetCultureInfo ("zh-CHT");
					//default:
					//	return GetCultureInfo (name);
					//}
					throw;
				}

				// used in runtime (icall.c) to construct CultureInfo for
				// AssemblyName of assemblies
				/*internal*/ static GC_PTR<CultureInfo> CreateCulture (string* name, bool reference)
				{
					//bool read_only;
					//bool use_user_override;
					//
					//bool invariant = name->Length == 0;
					//if (reference) {
					//	use_user_override = invariant ? false : true;
					//	read_only = false;
					//} else {
					//	read_only = false;
					//	use_user_override = invariant ? false : true;
					//}
					//
					//return new CultureInfo (name, use_user_override, read_only);
					throw;
				}

				public: static GC_PTR<CultureInfo> CreateSpecificCulture (string* name)
				{
					//if (name == null)
					//	throw ArgumentNullException ("name");
					//
					//if (name->Length == 0)
					//	return InvariantCulture;
					//
					//var src_name = name;
					//name = name->ToLowerInvariant ();
					//GC_PTR<CultureInfo> ci = new CultureInfo ();
					//
					//if (!ci->construct_internal_locale_from_name (name)) {
					//	int idx = name->IndexOf ('-');
					//	if (idx < 1 || !ci->construct_internal_locale_from_name (name->Substring (0, idx)))
					//		throw CreateNotFoundException (src_name);
					//}
					//
					//if (ci->IsNeutralCulture)
					//	ci = CreateSpecificCultureFromNeutral (ci->Name);
					//
					//return ci;
					throw;
				}

				//
				// Creates specific culture from neutral culture. Used by CreateSpecificCulture
				// only but using separate method we can delay switch underlying Dictionary
				// initialization
				//
				static GC_PTR<CultureInfo> CreateSpecificCultureFromNeutral (string* name)
				{
					//int id;
					//
					////
					//// For neutral cultures find predefined default specific culture
					////
					//// Use managed switch because we need this for only some cultures
					//// and the method is not used frequently
					////
					//// TODO: We could optimize for cultures with single specific culture 
					////
					//switch (name->ToLowerInvariant ()) {
					//case "af": id = 1078; break;
					//case "am": id = 1118; break;
					//case "ar": id = 1025; break;
					//case "arn": id = 1146; break;
					//case "as": id = 1101; break;
					//case "az": id = 1068; break;
					//case "az-Cyrl": id = 2092; break;
					//case "az-Latn": id = 1068; break;
					//case "ba": id = 1133; break;
					//case "be": id = 1059; break;
					//case "bg": id = 1026; break;
					//case "bn": id = 1093; break;
					//case "bo": id = 1105; break;
					//case "br": id = 1150; break;
					//case "bs": id = 5146; break;
					//case "bs-Cyrl": id = 8218; break;
					//case "bs-Latn": id = 5146; break;
					//case "ca": id = 1027; break;
					//case "co": id = 1155; break;
					//case "cs": id = 1029; break;
					//case "cy": id = 1106; break;
					//case "da": id = 1030; break;
					//case "de": id = 1031; break;
					//case "dsb": id = 2094; break;
					//case "dv": id = 1125; break;
					//case "el": id = 1032; break;
					//case "en": id = 1033; break;
					//case "es": id = 3082; break;
					//case "et": id = 1061; break;
					//case "eu": id = 1069; break;
					//case "fa": id = 1065; break;
					//case "fi": id = 1035; break;
					//case "fil": id = 1124; break;
					//case "fo": id = 1080; break;
					//case "fr": id = 1036; break;
					//case "fy": id = 1122; break;
					//case "ga": id = 2108; break;
					//case "gd": id = 1169; break;
					//case "gl": id = 1110; break;
					//case "gsw": id = 1156; break;
					//case "gu": id = 1095; break;
					//case "ha": id = 1128; break;
					//case "ha-Latn": id = 1128; break;
					//case "he": id = 1037; break;
					//case "hi": id = 1081; break;
					//case "hr": id = 1050; break;
					//case "hsb": id = 1070; break;
					//case "hu": id = 1038; break;
					//case "hy": id = 1067; break;
					//case "id": id = 1057; break;
					//case "ig": id = 1136; break;
					//case "ii": id = 1144; break;
					//case "is": id = 1039; break;
					//case "it": id = 1040; break;
					//case "iu": id = 2141; break;
					//case "iu-Cans": id = 1117; break;
					//case "iu-Latn": id = 2141; break;
					//case "ja": id = 1041; break;
					//case "ka": id = 1079; break;
					//case "kk": id = 1087; break;
					//case "kl": id = 1135; break;
					//case "km": id = 1107; break;
					//case "kn": id = 1099; break;
					//case "ko": id = 1042; break;
					//case "kok": id = 1111; break;
					//case "ky": id = 1088; break;
					//case "lb": id = 1134; break;
					//case "lo": id = 1108; break;
					//case "lt": id = 1063; break;
					//case "lv": id = 1062; break;
					//case "mi": id = 1153; break;
					//case "mk": id = 1071; break;
					//case "ml": id = 1100; break;
					//case "mn": id = 1104; break;
					//case "mn-Cyrl": id = 1104; break;
					//case "mn-Mong": id = 2128; break;
					//case "moh": id = 1148; break;
					//case "mr": id = 1102; break;
					//case "ms": id = 1086; break;
					//case "mt": id = 1082; break;
					//case "nb": id = 1044; break;
					//case "ne": id = 1121; break;
					//case "nl": id = 1043; break;
					//case "nn": id = 2068; break;
					//case "no": id = 1044; break;
					//case "nso": id = 1132; break;
					//case "oc": id = 1154; break;
					//case "or": id = 1096; break;
					//case "pa": id = 1094; break;
					//case "pl": id = 1045; break;
					//case "prs": id = 1164; break;
					//case "ps": id = 1123; break;
					//case "pt": id = 1046; break;
					//case "qut": id = 1158; break;
					//case "quz": id = 1131; break;
					//case "rm": id = 1047; break;
					//case "ro": id = 1048; break;
					//case "ru": id = 1049; break;
					//case "rw": id = 1159; break;
					//case "sa": id = 1103; break;
					//case "sah": id = 1157; break;
					//case "se": id = 1083; break;
					//case "si": id = 1115; break;
					//case "sk": id = 1051; break;
					//case "sl": id = 1060; break;
					//case "sma": id = 7227; break;
					//case "smj": id = 5179; break;
					//case "smn": id = 9275; break;
					//case "sms": id = 8251; break;
					//case "sq": id = 1052; break;
					//case "sr": id = 9242; break;
					//case "sr-Cyrl": id = 10266; break;
					//case "sr-Latn": id = 9242; break;
					//case "sv": id = 1053; break;
					//case "sw": id = 1089; break;
					//case "syr": id = 1114; break;
					//case "ta": id = 1097; break;
					//case "te": id = 1098; break;
					//case "tg": id = 1064; break;
					//case "tg-Cyrl": id = 1064; break;
					//case "th": id = 1054; break;
					//case "tk": id = 1090; break;
					//case "tn": id = 1074; break;
					//case "tr": id = 1055; break;
					//case "tt": id = 1092; break;
					//case "tzm": id = 2143; break;
					//case "tzm-Latn": id = 2143; break;
					//case "ug": id = 1152; break;
					//case "uk": id = 1058; break;
					//case "ur": id = 1056; break;
					//case "uz": id = 1091; break;
					//case "uz-Cyrl": id = 2115; break;
					//case "uz-Latn": id = 1091; break;
					//case "vi": id = 1066; break;
					//case "wo": id = 1160; break;
					//case "xh": id = 1076; break;
					//case "yo": id = 1130; break;
					//case "zh": id = 2052; break;
					//case "zh-CHS": case "zh-Hans": id = 2052; break;
					//case "zh-CHT": case "zh-Hant": id = 3076; break;
					//case "zu": id = 1077; break;
					//default:
					//	throw NotImplementedException (string("Mapping for neutral culture ") + *name);
					//}
					//
					//return new CultureInfo (id);
					throw;
				}

				static GC_PTR<Calendar> CreateCalendar (int calendarType)
				{
					//GC_PTR<string> name = null;
					//switch (calendarType >> CalendarTypeBits) {
					//case 1:
					//	GregorianCalendarTypes greg_type;
					//	greg_type = (GregorianCalendarTypes) (calendarType & 0xFF);
					//	return new GregorianCalendar (greg_type);
					//case 2:
					//	name = "System.Globalization.ThaiBuddhistCalendar";
					//	break;
					//case 3:
					//	name = "System.Globalization.UmAlQuraCalendar";
					//	break;
					//case 4:
					//	name = "System.Globalization.HijriCalendar";
					//	break;
					//default:
					//	throw NotImplementedException ("Unknown _calendar type: " + calendarType);
					//}
					//
					//GC_PTR<Type> type = Type::GetType (name, false);
					//if (type == null)
					//	return CreateCalendar (1 << CalendarTypeBits); // return invariant calandar if not found
					//return (Calendar*) Activator::CreateInstance (type);
					throw;
				}

				static GC_PTR<Exception> CreateNotFoundException (string* name)
				{
					//return new CultureNotFoundException ("name", "Culture name " + name + " is not supported.");
					throw;
				}
		
		//#if NET_4_5
		//		public: static CultureInfo DefaultThreadCurrentCulture {
		//			get {
		//				return Thread.default_culture;
		//			}
		//			set {
		//				Thread.default_culture = value;
		//			}
		//		}
		//
		//		public: static CultureInfo DefaultThreadCurrentUICulture {
		//			get {
		//				return Thread.default_ui_culture;
		//			}
		//			set {
		//				Thread.default_ui_culture = value;
		//			}
		//		}
		//#endif
			};
		}
	}
}

#endif